package cn.demoncat.util.lang;

import cn.demoncat.util.exception.ParamRuntimeException;
import cn.demoncat.util.lang.constant.LongConstant;
import cn.demoncat.util.lang.constant.StringConstant;
import cn.demoncat.util.lang.fn.Consumer2;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;

/**
 * 描述：金额相关工具
 *
 * 注意：金额最大为15,2位（13位整数），否则转换字符串时错误
 *
 * @author 延晓磊
 *
 * @since 2017年3月23日
 */
public final class MoneyUtil {

	/**
	 * 最小金额：0.01
	 */
	public static final BigDecimal MIN = BigDecimal.valueOf(0.01);
	/**
	 * 最大金额：15,2
	 */
	public static final BigDecimal MAX = new BigDecimal("9999999999999.99");

	// 大写
	private static final char[] BIG_HUNIT = new char[]{ '拾', '佰', '仟' };
	private static final char[] BIG_VUNIT = new char[]{ '万', '亿', '万' };
	private static final char[] BIG_DIGIT = new char[]{ '零', '壹', '贰', '叁', '肆', '伍', '陆', '柒', '捌', '玖' };
	// 小写
	private static final char[] HUNIT = new char[]{ '十', '百', '千' };
	private static final char[] VUNIT = new char[]{ '万', '亿', '万' };
	private static final char[] DIGIT = new char[]{ '零', '一', '二', '三', '四', '五', '六', '七', '八', '九' };
	
	/**
	 * 功能描述：数字型金额转换为汉字金额(最多处理千万亿级)
	 *
	 * @param money 数字型金额：单位为分
	 * @param isBig 是否为大写金额汉字：true 壹,false 一
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年3月23日
	 */
	public static String toChinese(String money, boolean isBig) {
		//特殊值处理
		if (StringUtils.isBlank(money) || StringConstant.N0.equals(money)) {
			return "零元";
		}
		//校验
		boolean matcher = RegexpUtil.matcher(money, RegexpUtil.NumberRex.POSITIVE_INTEGER);
		if (!matcher) {
			throw new ParamRuntimeException("金额必须为正整数");
		}else if (money.length() > 18) {
			throw new ParamRuntimeException("最大转换千万亿级的金额");
		}
		//汉字
		char[] hunit;
		char[] vunit;
		char[] digit;
		if (isBig) {
			hunit = BIG_HUNIT;
			vunit = BIG_VUNIT;
			digit = BIG_DIGIT;
		}else{
			hunit = HUNIT;
			vunit = VUNIT;
			digit = DIGIT;
		}
		//小额处理
		if (money.length() == 2) {
			// char - char = int === Integer.valueOf(String.valueOf(char)) 
			return digit[money.charAt(0) - '0'] + "角" + digit[money.charAt(1) - '0'] + "分";
		}else if (money.length() == 1) {
			return digit[money.charAt(0) - '0'] + "分";
		}
		// 分割元和分
		String head = money.substring(0, money.length() - 2);
		String rail = money.substring(money.length() - 2);
		StringBuilder prefix = new StringBuilder();
		String suffix;
		// 处理分
		if (rail.equals("00")) {
			suffix = "整";
		} else {
			suffix = digit[rail.charAt(0) - '0'] + "角" + digit[rail.charAt(1) - '0'] + "分";
		}
		// 处理元
		char[] chDig = head.toCharArray();
		// 标志当前位的上一位是否为有效0位
		boolean preZero = false;
		// 连续出现0的次数
		byte zeroSerNum = 0;
		// 循环处理每个数字
		for (int i = 0; i < chDig.length; i++) {
			// 取段内位置
			int idx = (chDig.length - i - 1) % 4;
			// 取段位置
			int vidx = (chDig.length - i - 1) / 4;
			// 如果当前字符是0
			if (chDig[i] == '0') {
				preZero = true;
				// 连续0次数递增
				zeroSerNum++;
				if (idx == 0 && vidx > 0 && zeroSerNum < 4) {
					prefix.append(vunit[vidx - 1]);
					preZero = false;
				}
			} else {
				// 连续0次数清零
				zeroSerNum = 0;
				// 上一位为有效0位
				if (preZero) {
					prefix.append(digit[0]);
					preZero = false;
				}
				// 转化该数字表示
				prefix.append(digit[chDig[i] - '0']);
				if (idx > 0)
					prefix.append(hunit[idx - 1]);
				if (idx == 0 && vidx > 0) {
					// 段结束位置应该加上段名如万,亿
					prefix.append(vunit[vidx - 1]);

				}
			}
		}
		return prefix.append("元").append(suffix).toString();
	}
	
	/**
	 * 功能描述：数字型金额转换为汉字金额（最多处理千万亿级）
	 *
	 * @param money 数字型金额：单位为分
	 * @param isBig 是否为大写金额汉字：true 壹,false 一
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年3月23日
	 */
	public static String toChinese(long money, boolean isBig) {
		return toChinese(NumberUtil.toString(money), isBig);
	}
	
	/**
	 * 功能描述：数字型金额转换为汉字金额（最多处理千万亿级；因为大金额会用科学计数法导致偏移，所以万亿级以上小数位有可能出现差错，应慎用）
	 *
	 * @param money 数字型金额：单位为元
	 * @param isBig 是否为大写金额汉字：true 壹,false 一
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年3月23日
	 */
	public static String toChinese(double money, boolean isBig) {
		return toChinese(toFen(money), isBig);
	}
	
	/**
	 * 功能描述：数字型金额转换为汉字金额（最多处理千万亿级；因为大金额会用科学计数法导致偏移，所以万亿级以上小数位有可能出现差错，应慎用）
	 *
	 * @param money 数字型金额：单位为元
	 * @param isBig 是否为大写金额汉字：true 壹,false 一
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年3月23日
	 */
	public static String toChinese(BigDecimal money, boolean isBig) {
		return toChinese(toFen(money), isBig);
	}
	
	/**
	 * 转换为字符串
	 * 
	 * @param money	元
	 * 
	 * @return  字符串：0.00
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年12月4日
	 */
	public static String toStr(BigDecimal money){
		return NumberUtil.format(money, NumberUtil.Format.DOUBLE);
	}
	
	/**
	 * 转换为字符串
	 * 
	 * @param money	分
	 * 
	 * @return  字符串：0.00
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年12月4日
	 */
	public static String toStr(Long money){
		return toStr(toYuan(money));
	}
	
	/**
	 * 转换为字符串
	 * 
	 * @param money	分
	 * 
	 * @return  字符串：0.00
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年12月4日
	 */
	public static String toStr(String money){
		return toStr(toYuan(money));
	}
	
	/**
	 * 分转元
	 * 
	 * @param fen
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年12月4日
	 */
	public static BigDecimal toYuan(Long fen){
		if (NumberUtil.isBlank(fen)) {
			return BigDecimal.ZERO;
		}
		return MoneyUtil.computePrice(BigDecimal.valueOf(fen), 100L);
	}
	
	/**
	 * 分转元
	 * 
	 * @param fen
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年12月4日
	 */
	public static BigDecimal toYuan(String fen){
		return toYuan(LongUtil.valueOfZero(fen));
	}

	/**
	 * 元转分
	 * 
	 * @param yuan
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年12月4日
	 */
	public static Long toFen(String yuan){
		// 直接转换方式：处理特大金额时会出错
		// return (long)(DoubleUtil.valueOf(yuan) * 100);
		
		// 参数校验
		if (StringUtils.isBlank(yuan) || StringConstant.N0.equals(yuan)) {
			return LongConstant.N0;
		}
		// 字符串切割方式
		String[] arr = yuan.split("\\.");
		if (arr.length == 1) {
			yuan = arr[0] +StringConstant.N00;
		}else{
			String fen = arr[1];
			if (fen.length() == 1) {
				yuan = arr[0] + fen +StringConstant.N0;
			} else if (fen.length() == 2) {
				yuan = arr[0] + fen;
			} else{
				yuan = arr[0] + fen.substring(0,2);
			}
		}
		return Long.valueOf(yuan);
	}
	
	/**
	 * 元转分
	 * 
	 * @param num
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年12月4日
	 */
	public static Long toFen(BigDecimal num){
		if (NumberUtil.isBlank(num)) {
			return LongConstant.N0;
		}
		return toFen(num.toPlainString());
	}
	
	/**
	 * 元转分
	 * 
	 * @param num
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年12月4日
	 */
	public static Long toFen(Double num){
		if (NumberUtil.isBlank(num)) {
			return LongConstant.N0;
		}
		return toFen(NumberUtil.toString(num));
	}

	/**
	 * 金额格式化 - 入金
	 *
	 * 规则：2位小数，向上进位
	 * 场景：用户向平台支付（向用户多收，保证后期能正确的分账）
	 * 
	 * @param amount
	 * 
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年1月9日
	 */
	public static BigDecimal format(BigDecimal amount) {
		return DecimalUtil.toCeil(amount, 2);
	}

	/**
	 * 金额格式化 - 出金
	 *
	 * 规则：2位小数，向下进位
	 * 场景：平台向用户支付（防止小额套现的漏洞）、结算佣金计算（平台少收佣金，防止小额交易的佣金收取不合理）
	 *
	 * @param amount
	 *
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2020年1月9日
	 */
	public static BigDecimal formatOut(BigDecimal amount) {
		return DecimalUtil.toFloor(amount, 2);
	}
	
	/**
	 * 计算折扣率（百分比值）
	 *
	 * 规则：整数，向下进位
	 * 
	 * @param price				原价
	 * @param discountPrice		折扣价
	 * 
	 * @return 折扣率
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年3月10日
	 */
	public static int computeDiscountPercent(BigDecimal price, BigDecimal discountPrice) {
		return DecimalUtil.parsePercent(computeDiscount(price, discountPrice));
	}
	
	/**
	 * 计算折扣率（小数值）
	 *
	 * 规则：2位小数，向下进位
	 * 
	 * @param price				原价
	 * @param discountPrice		折扣价
	 * 
	 * @return 0.00
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年3月10日
	 */
	public static BigDecimal computeDiscount(BigDecimal price, BigDecimal discountPrice) {
		return DecimalUtil.toRatio(price, discountPrice);
	}

	/**
	 * 计算折扣价 - 入金
	 *
	 * 规则：2位小数，向上进位
	 * 
	 * @param price			原价
	 * @param discount		折扣率
	 * 
	 * @return 折扣价(舍余数)
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年3月10日
	 */
	public static BigDecimal computeDiscountPrice(BigDecimal price, BigDecimal discount) {
		return discount.equals(BigDecimal.ONE) ? price : format(price.multiply(discount));
	}

	/**
	 * 计算折扣价 - 出金
	 *
	 * 规则：2位小数，向下进位
	 *
	 * @param price			原价
	 * @param discount		折扣率
	 *
	 * @return 折扣价(舍余数)
	 *
	 * @author 延晓磊
	 *
	 * @since 2020年3月10日
	 */
	public static BigDecimal computeOutDiscountPrice(BigDecimal price, BigDecimal discount) {
		return discount.equals(BigDecimal.ONE) ? price : formatOut(price.multiply(discount));
	}
	
	/**
	 * 计算折扣价 - 入金
	 *
	 * 规则：2位小数，向上进位
	 * 
	 * @param price			原价
	 * @param discount		折扣率(百分比值)
	 * 
	 * @return 折扣价(舍余数)
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年3月10日
	 */
	public static BigDecimal computeDiscountPrice(BigDecimal price, int discount) {
		return computeDiscountPrice(price, DecimalUtil.parsePercent(discount));
	}

	/**
	 * 计算折扣价 - 出金
	 *
	 * 规则：2位小数，向下进位
	 *
	 * @param price			原价
	 * @param discount		折扣率(百分比值)
	 *
	 * @return 折扣价(舍余数)
	 *
	 * @author 延晓磊
	 *
	 * @since 2020年3月10日
	 */
	public static BigDecimal computeOutDiscountPrice(BigDecimal price, int discount) {
		return computeOutDiscountPrice(price, DecimalUtil.parsePercent(discount));
	}

	/**
	 * 计算税率
	 * 
	 * @param price				含税价
	 * @param untaxedPrice		未税价
	 * @return 税率：0.00
	 * 
	 * @author 延晓磊
	 * @since 2024年02月21日
	 */
	public static BigDecimal computeTax(BigDecimal price, BigDecimal untaxedPrice){
		return price.subtract(untaxedPrice).divide(untaxedPrice, 2, RoundingMode.HALF_UP);
	}

	/**
	 * 计算含价价
	 *
	 * @param untaxedPrice		未税价
	 * @param tax				税率：0.00
	 * @return 含税价
	 *
	 * @author 延晓磊
	 * @since 2024年02月21日
	 */
	public static BigDecimal computeTaxPrice(BigDecimal untaxedPrice, BigDecimal tax){
		return  tax.add(BigDecimal.ONE).multiply(untaxedPrice).setScale(2, RoundingMode.HALF_UP);
	}

	/**
	 * 计算含价价
	 *
	 * @param untaxedPrice		未税价
	 * @param tax				税率：13
	 * @return 含税价
	 *
	 * @author 延晓磊
	 * @since 2024年02月21日
	 */
	public static BigDecimal computeTaxPrice(BigDecimal untaxedPrice, Integer tax){
		return  BigDecimal.valueOf(tax).multiply(BigDecimal.valueOf(0.01)).add(BigDecimal.ONE).multiply(untaxedPrice).setScale(2, RoundingMode.HALF_UP);
	}

	/**
	 * 计算未价价
	 *
	 * @param price				含税价
	 * @param tax				税率：0.00
	 * @return 未税价
	 *
	 * @author 延晓磊
	 * @since 2024年02月21日
	 */
	public static BigDecimal computeUntaxedPrice(BigDecimal price, BigDecimal tax){
		return price.divide(tax.add(BigDecimal.ONE), 2, RoundingMode.HALF_UP);
	}

	/**
	 * 计算未价价
	 *
	 * @param price				含税价
	 * @param tax				税率：13
	 * @return 未税价
	 *
	 * @author 延晓磊
	 * @since 2024年02月21日
	 */
	public static BigDecimal computeUntaxedPrice(BigDecimal price, Integer tax){
		return price.divide(BigDecimal.valueOf(tax).multiply(BigDecimal.valueOf(0.01)).add(BigDecimal.ONE), 2, RoundingMode.HALF_UP);
	}

	/**
	 * 计算手续费率
	 *
	 * 规则：length位小数，向上进位
	 * 
	 * @param rate		基准费率
	 * @param discount	折扣率
	 * @param length	长度
	 * 
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年1月9日
	 */
	public static BigDecimal computeChargeRate(BigDecimal rate, BigDecimal discount, int length) {
		return DecimalUtil.isGt(rate) ? DecimalUtil.toCeil(rate.multiply(discount), length) : BigDecimal.ZERO;
	}

	/**
	 * 计算手续费率
	 *
	 * 规则：4位小数，向上进位
	 *
	 * @param rate		基准费率
	 * @param discount	折扣率
	 *
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2020年1月9日
	 */
	public static BigDecimal computeChargeRate(BigDecimal rate, BigDecimal discount) {
		return computeChargeRate(rate, discount, 4);
	}
	
	/**
	 * 计算手续费 - 入金
	 *
	 * 场景：用户支付
	 * 规则：2位小数，向上进位
	 *
	 * @param amount	总额
	 * @param rate		费率：0-1
	 * 
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年1月9日
	 */
	public static BigDecimal computeCharge(BigDecimal amount, BigDecimal rate) {
		return DecimalUtil.isGt(rate) ? format(amount.multiply(rate)) : BigDecimal.ZERO;
	}

	/**
	 * 计算手续费 - 出金
	 *
	 * 场景：收取佣金（平台少收佣金，防止小额交易的佣金收取不合理）
	 * 规则：2位小数，向下进位
	 *
	 * @param amount	总额
	 * @param rate		费率：0-1
	 *
	 * @return
	 *
	 * @author 延晓磊
	 *
	 * @since 2020年1月9日
	 */
	public static BigDecimal computeChargeOut(BigDecimal amount, BigDecimal rate) {
		return DecimalUtil.isGt(rate) ? formatOut(amount.multiply(rate)) : BigDecimal.ZERO;
	}
	
	/**
	 * 计算手续费 - 入金
	 *
	 * 场景：用户支付
	 * 规则：2位小数，向上进位
	 * 
	 * @param num		数量
	 * @param price		单价
	 * @param rate		费率
	 * 
	 * @return 2位小数，向上进位
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年1月9日
	 */
	public static BigDecimal computeCharge(long num, BigDecimal price, BigDecimal rate) {
		return computeCharge(BigDecimal.valueOf(num).multiply(price), rate);
	}

	/**
	 * 计算手续费 - 出金
	 *
	 * 场景：收取佣金
	 * 规则：2位小数，向下进位
	 *
	 * @param num		数量
	 * @param price		单价
	 * @param rate		费率
	 *
	 * @return 2位小数，向下进位
	 *
	 * @author 延晓磊
	 *
	 * @since 2020年1月9日
	 */
	public static BigDecimal computeChargeOut(long num, BigDecimal price, BigDecimal rate) {
		return computeChargeOut(BigDecimal.valueOf(num).multiply(price), rate);
	}

	/**
	 * 计算总金额 - 入金
	 *
	 * 规则：2位小数，向上进位
	 *
	 * @param num		数量
	 * @param price		单价
	 * 
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年1月9日
	 */
	public static BigDecimal computeAmount(long num, BigDecimal price) {
		return format(BigDecimal.valueOf(num).multiply(price));
	}
	
	/**
	 * 计算总金额 - 出金
	 *
	 * 规则：2位小数，向下进位
	 *
	 * @param num		数量
	 * @param price		单价
	 * 
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年1月9日
	 */
	public static BigDecimal computeAmountOut(long num, BigDecimal price) {
		return formatOut(BigDecimal.valueOf(num).multiply(price));
	}
	
	/**
	 * 计算单价 - 入金
	 *
	 * 规则：2位小数，向上进位
	 *
	 * @param amount	金额
	 * @param num		数量
	 * 
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年1月9日
	 */
	public static BigDecimal computePrice(BigDecimal amount, long num) {
		return DecimalUtil.divide(2, RoundingMode.CEILING, amount, BigDecimal.valueOf(num));
	}

	/**
	 * 扣减数量：-
	 *
	 * @param msg		错误消息
	 * @param nums		数量
	 *
	 * @return 结果为负时抛异常"msg"
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年1月9日
	 */
	public static long computeSubtract(String msg, long ...nums) {
		return LongUtil.subtractZero(msg, nums);
	}

	/**
	 * 扣减数量：-
	 *
	 * @param nums		数量
	 *
	 * @return 结果为负时抛异常"数量不足"
	 *
	 * @author 延晓磊
	 *
	 * @since 2020年1月9日
	 */
	public static long computeSubtract(long ...nums) {
		return computeSubtract("数量不足", nums);
	}

	/**
	 * 扣减金额：-
	 *
	 * @param msg		错误消息，结果为负时抛异常
	 * @param amounts	金额
	 *
	 * @return 结果为负时抛异常"msg"
	 *
	 * @author 延晓磊
	 *
	 * @since 2020年1月9日
	 */
	public static BigDecimal computeSubtract(String msg, BigDecimal ...amounts) {
		return DecimalUtil.subtractZero(msg, amounts);
	}

	/**
	 * 扣减金额：-
	 * 
	 * @param amounts	金额
	 *
	 * @return 结果为负时抛异常"余额不足"
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年1月9日
	 */
	public static BigDecimal computeSubtract(BigDecimal ...amounts) {
		return computeSubtract("余额不足", amounts);
	}

	/**
	 * 金额校验
	 *
	 * @param amount
	 * @param desc		目标：如"商品价格"、"订单金额"，默认"金额"
	 * @return MIN-MAX
	 *
	 * @author 延晓磊
	 * @since 2021年03月05日
	 */
	public static BigDecimal check(BigDecimal amount, String desc){
		if(StringUtils.isBlank(desc)){
			desc = "金额";
		}
		if (amount == null) {
			throw new ParamRuntimeException(desc + "不能为空");
		}
		if (DecimalUtil.isLt(amount, MIN)) {
			throw new ParamRuntimeException(desc + "不能小于0.01元");
		}
		if (DecimalUtil.isGt(amount, MAX)) {
			throw new ParamRuntimeException(desc + "过大");
		}
		return amount;
	}

	/**
	 * 分摊金额
	 *
	 * 1、计算数据的总金额
	 * 2、计算数据的金额占比
	 * 3、根据数据的占比分摊金额（向下进位；出现精度问题时，由最大数据分摊）
	 *
	 * @param amount	分摊金额：0.00
	 * @param list		分摊数据
	 * @param getter	获取数据的金额（计算分摊比例）
	 * @param setter	设置数据的分摊金额
	 * @return
	 *
	 * @author 延晓磊
	 * @since 2021年03月14日
	 */
	public static <O>List<O> split(BigDecimal amount, List<O> list, Function<O,BigDecimal> getter, Consumer2<O,BigDecimal> setter){
		// list.size = 0
		if (CollectionUtils.isEmpty(list)) {
			return list;
		}
		// list.size = 1
		if (list.size() == 1) {
			// 设置分摊金额
			setter.accept(list.get(0), amount);
			return list;
		}
		// list.size > 1
		if (DecimalUtil.isEq(amount)) {
			// 分摊金额 == 0
			for (O o : list) {
				setter.accept(o, BigDecimal.ZERO);
			}
		}else{
			// 分摊金额 > 0
			BigDecimal total = BigDecimal.ZERO;
			for (O o : list) {
				// 计算数据总金额
				total = total.add(getter.apply(o));
			}
			// 按比例分摊金额
			BigDecimal residual = amount;
			BigDecimal curr;
			for (O o : list) {
				// 数据金额
				curr = getter.apply(o);
				if (DecimalUtil.isEq(curr)) {
					// 可分摊金额 == 0
					setter.accept(o, BigDecimal.ZERO);
				}else{
					// 计算分摊金额（舍弃精度）
					curr = curr.multiply(amount).divide(total,2,RoundingMode.FLOOR);
					if (DecimalUtil.isEq(curr)) {
						// 可分摊金额 == 0
						setter.accept(o, BigDecimal.ZERO);
					}else{
						// 设置分摊金额
						setter.accept(o, curr);
						// 递减剩余金额
						residual = residual.subtract(curr);
					}
				}
			}
			// 剩余金额 > 0
			if (DecimalUtil.isGt(residual)) {
				// 获取最大数据
				BigDecimal max = BigDecimal.ZERO;
				for (O o : list) {
				   	if (DecimalUtil.isGt(getter.apply(o), max)) {
				   		max = getter.apply(o);
				   	}
				}
				List<O> maxList = new ArrayList<>();
				for (O o : list) {
				    if (DecimalUtil.isEq(getter.apply(o), max)) {
				    	maxList.add(o);
				    }
				}
				// 计算最大数据的已分摊金额
				curr = max.multiply(amount).divide(total,2,RoundingMode.FLOOR);
				// 分摊剩余金额
				if (maxList.size() == 1 || DecimalUtil.isEq(residual,MIN)) {
					// 单个最大值 | 剩余0.01 = 直接分摊
					setter.accept(maxList.get(0), curr.add(residual));
				}else{
					// 计算分摊金额
					List<BigDecimal> maxValueList = new ArrayList<>(maxList.size());
					for (int i = 0; i < maxList.size(); i++) {
						maxValueList.add(curr);
					}
					int index;
					for (int i = 0; i < residual.divide(MIN,0,RoundingMode.FLOOR).intValue(); i++) {
						index = i % maxValueList.size();
						maxValueList.set(index, maxValueList.get(index).add(MIN));
					}
					// 设置分摊金额
					for (int i = 0; i < maxList.size(); i++) {
						setter.accept(maxList.get(i), maxValueList.get(i));
					}
				}
			}
		}
		return list;
	}

}
